home *** CD-ROM | disk | FTP | other *** search
/ FM Towns: Free Software Collection 7 / FM Towns Free Software Collection 7.iso / taropyon / zmodem / src / rz.c < prev    next >
C/C++ Source or Header  |  1993-11-30  |  35KB  |  1,631 lines

  1. #define    __TOWNS__
  2. #define VERSION "3.04 02-20-91"
  3. #define PUBDIR "/usr/spool/uucppublic"
  4.  
  5. /*
  6.  * rz.c By Chuck Forsberg
  7.  *
  8.  * A program for Unix to receive files and commands from computers running
  9.  * Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM. rz
  10.  * uses Unix buffered input to reduce wasted CPU time.
  11.  *
  12.  *
  13.  * This version implements numerous enhancements including ZMODEM Run Length
  14.  * Encoding and variable length headers.  These features were not funded by
  15.  * the original Telenet development contract.
  16.  *
  17.  * This software may be freely used for non commercial and educational (didactic
  18.  * only) purposes.    This software may also be freely used to support file
  19.  * transfer operations to or from licensed Omen Technology products.  Any
  20.  * programs which use part or all of this software must be provided in source
  21.  * form with this notice intact except by written permission from Omen
  22.  * Technology Incorporated.
  23.  *
  24.  * Use of this software for commercial or administrative purposes except when
  25.  * exclusively limited to interfacing Omen Technology products requires a per
  26.  * port license payment of $20.00 US per port (less in quantity).  Use of
  27.  * this code by inclusion, decompilation, reverse engineering or any other
  28.  * means constitutes agreement to these conditions and acceptance of
  29.  * liability to license the materials and payment of reasonable legal costs
  30.  * necessary to enforce this license agreement.
  31.  *
  32.  *
  33.  * Omen Technology Inc            FAX: 503-621-3745 Post Office Box 4681
  34.  * Portland OR 97208
  35.  *
  36.  * This code is made available in the hope it will be useful, BUT WITHOUT ANY
  37.  * WARRANTY OF ANY KIND OR LIABILITY FOR ANY DAMAGES OF ANY KIND.
  38.  *
  39.  *
  40.  *
  41.  * Iff the program is invoked by rzCOMMAND, output is piped to "COMMAND
  42.  * filename"  (Unix only)
  43.  *
  44.  * Some systems (Venix, Coherent, Regulus) may not support tty raw mode read(2)
  45.  * the same way as Unix. ONEREAD must be defined to force one character reads
  46.  * for these systems. Added 7-01-84 CAF
  47.  *
  48.  * Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF
  49.  *
  50.  * NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN] doesn't work
  51.  * properly (even though it compiles without error!),
  52.  *
  53.  * SEGMENTS=n added 2-21-88 as a model for CP/M programs for CP/M-80 systems
  54.  * that cannot overlap modem and disk I/O.
  55.  *
  56.  * -DMD may be added to compiler command line to compile in Directory-creating
  57.  * routines from Public Domain TAR by John Gilmore
  58.  *
  59.  * HOWMANY may be tuned for best performance
  60.  *
  61.  * USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin */
  62.  
  63.  
  64. #define LOGFILE "/tmp/rzlog"
  65. #include <stdio.h>
  66. #include <signal.h>
  67. #include <setjmp.h>
  68. #include <ctype.h>
  69. #include <errno.h>
  70. extern int    errno;
  71.  
  72. #ifdef    __TOWNS__
  73. #    include    <string.h>
  74. #    include    <stdarg.h>
  75. #    include    <stdlib.h>
  76. #    include    <direct.h>
  77. #    include    <stat.h>
  78. #    include    <sys/types.h>
  79. #    include    <sys/utime.h>
  80. #    include    <io.h>
  81. #    include    <time.h>
  82.  
  83. #    include    <splib.h>
  84. #    include    <fslib.h>
  85.  
  86. #    include    "usrlib.h"
  87. #    include    "rsctrl.h"
  88. #    include    "flib.h"
  89. #    include    "msgdat.h"
  90.  
  91. #    ifdef    __HIGHC__
  92. #        pragma    On(Align_labels);
  93. #    endif
  94.  
  95.     extern    int    RsPort;
  96. #    define    _FSTAT_IGN
  97. #    define    MD
  98. #endif
  99. #include    "prot.h"
  100. #include    "rz.h"
  101.  
  102. int         Zmodem = 0;         /* ZMODEM protocol requested */
  103. int         Nozmodem = 0;        /* If invoked as "rb" */
  104. unsigned    Baudrate = 2400;
  105. unsigned    Effbaud = 2400;
  106.  
  107. #include "rbsb.c"                /* most of the system dependent stuff here */
  108. #include "crctab.c"
  109.  
  110. FILE       *fout = NULL;
  111.  
  112. /*
  113.  * Routine to calculate the free bytes on the current file system ~0 means
  114.  * many free bytes (unknown)
  115.  */
  116. static    long        getfree(void)
  117. {
  118. #ifdef    __TOWNS__
  119.     int        drv;
  120.     int        tf, wf;
  121.  
  122.     if ( (drv = FS_getdrv()) >= 0 )
  123.     {
  124.         if ( FS_get_dskFree( drv, &tf, &wf) == NORMAL )
  125.             return (long)tf;
  126.     }
  127. #endif
  128.     return (~0L);                /* many free bytes ... */
  129. }
  130.  
  131. int         Lastrx;
  132. long        rxbytes;
  133. int         Crcflg;
  134. int         Firstsec;
  135. int         Eofseen;            /* indicates cpm eof (^Z) has been received */
  136. int         errors;
  137. int         Restricted = 0;     /* restricted; no /.. or ../ in filenames */
  138. #ifdef ONEREAD
  139. /* Sorry, Regulus and some others don't work right in raw mode! */
  140. int         Readnum = 1;        /* Number of bytes to ask for in read() from
  141.                                  * modem */
  142. #else
  143. int         Readnum = HOWMANY;    /* Number of bytes to ask for in read() from
  144.                                  * modem */
  145. #endif
  146.  
  147. #define DEFBYTL 2000000000L     /* default rx file size */
  148. long        Bytesleft;            /* number of bytes of incoming file left */
  149. long        Modtime;            /* Unix style mod time for incoming file */
  150. int         Filemode;            /* Unix style mode for incoming file */
  151. long        Totalleft;
  152. long        Filesleft;
  153. char        Pathname[PATHLEN];
  154. char       *Progname;            /* the name by which we were called */
  155.  
  156. int         Batch = 0;
  157. int         Topipe = 0;
  158. int         Verbose = 0;
  159. int         Thisbinary;         /* current file is to be received in bin mode */
  160. int         Blklen;             /* record length of received packets */
  161.  
  162. #ifdef SEGMENTS
  163. int         chinseg = 0;        /* Number of characters received in this data seg */
  164. char        secbuf[1 + (SEGMENTS + 1) * 1024];
  165. #else
  166. char        secbuf[1025];
  167. #endif
  168.  
  169.  
  170. char        linbuf[HOWMANY];
  171. int         Lleft = 0;            /* number of characters in linbuf */
  172. time_t        timep[2];
  173. char        zconv;                /* ZMODEM file conversion request */
  174. char        zmanag;             /* ZMODEM file management request */
  175. char        ztrans;             /* ZMODEM file transport request */
  176. int         Zctlesc;            /* Encode control characters */
  177. int         Zrwindow = 1400;    /* RX window size (controls garbage count) */
  178.  
  179. jmp_buf     tohere;             /* For the interrupt on RX timeout */
  180.  
  181. #define xsendline(c) sendline(c)
  182.  
  183. #include "zm.c"
  184.  
  185. #include "zmr.c"
  186.  
  187. int         tryzhdrtype = ZRINIT;        /* Header type to send corresponding
  188.                                          * to Last rx close */
  189.  
  190. #ifdef    __TOWNS__
  191. void    signal_func(int level)
  192. {
  193. }
  194.  
  195. /* called by signal interrupt or terminate to clean things up */
  196. void    bibi(int n)
  197. {
  198.     if (Zmodem)
  199.         zmputs(Attn);
  200.     canit();
  201.     mode(0);
  202.     USR_fprintf(stderr, "rz: caught signal %d; exiting", n);
  203.     cucheck();
  204.     EXIT(128 + n);
  205. }
  206. #else
  207. void    alrm(int level)
  208. {
  209.     longjmp(tohere, -1);
  210. }
  211.  
  212. /* called by signal interrupt or terminate to clean things up */
  213. bibi(int n)
  214. {
  215.     if (Zmodem)
  216.         zmputs(Attn);
  217.     canit();
  218.     mode(0);
  219.     fprintf(stderr, "rz: caught signal %d; exiting", n);
  220.     cucheck();
  221.     exit(128 + n);
  222. }
  223. #endif
  224.  
  225. void    zm_main(int argc, char *argv[])
  226. {
  227.     register char *cp;
  228.     register    npats;
  229.     char       *virgin, **patts;
  230.     int         exitcode = 0;
  231.  
  232.     Rxtimeout = 100;
  233. //    setbuf(stderr, NULL);
  234. #if    0
  235.     if ((cp = getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  236.         Restricted = TRUE;    /* 制限    */
  237. #endif
  238.  
  239.     from_cu();
  240.     chkinvok(virgin = argv[0]); /* if called as [-]rzCOMMAND set flag */
  241.     npats = 0;
  242.     while (--argc)
  243.     {
  244.         cp = *++argv;
  245.         if (*cp == '-')
  246.         {
  247.             while (*++cp)
  248.             {
  249.                 switch (*cp)
  250.                 {
  251.                     case '\\':
  252.                         cp[1] = toupper(cp[1]);
  253.                         continue;
  254.                     case 'c':
  255.                         Crcflg = TRUE;
  256.                         break;
  257.                     case 'e':
  258.                         Zctlesc = 1;
  259.                         break;
  260.                     case 't':
  261.                         if (--argc < 1)
  262.                         {
  263.                             usage();
  264.                         }
  265.                         Rxtimeout = atoi(*++argv);
  266.                         if (Rxtimeout < 10 || Rxtimeout > 1000)
  267.                             usage();
  268.                         break;
  269.                     case 'w':
  270.                         if (--argc < 1)
  271.                         {
  272.                             usage();
  273.                         }
  274.                         Zrwindow = atoi(*++argv);
  275.                         break;
  276.                     case 'v':
  277.                         ++Verbose;
  278.                         break;
  279.                     default:
  280.                         usage();
  281.                 }
  282.             }
  283.         } else if (!npats && argc > 0)
  284.         {
  285.             if (argv[0][0])
  286.             {
  287.                 npats = argc;
  288.                 patts = argv;
  289.             }
  290.         }
  291.     }
  292.     if (npats > 1)
  293.         usage();
  294.     if (Batch && npats)
  295.         usage();
  296. #ifndef    __TOWNS__
  297.     if (Verbose)
  298.     {
  299.         if ( freopen(LOGFILE, "a", stderr) == NULL )
  300.         {
  301.             printf("Can't open log file %s\n", LOGFILE);
  302.             exit(0200);
  303.         }
  304. //        setbuf(stderr, NULL);
  305.         USR_fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
  306.     }
  307. #endif
  308.     if (Fromcu)
  309.     {
  310.         if (Verbose == 0)
  311.             Verbose = 2;
  312.     }
  313. #ifdef    __TOWNS__
  314.     USR_fprintf(stderr,"\n");
  315.     USR_fprintf(stderr,"rz ver.%s for TownsOS", MAIN_VER );
  316.     USR_fprintf(stderr,"    orignal rz %s\n\n", VERSION);
  317. #else
  318.     vfile("%s %s for %s\n", Progname, VERSION, OS);
  319. #endif
  320.     mode(1);    /* save old tty stat, set raw mode */
  321. #ifndef    __TOWNS__
  322.     if (signal(SIGINT, bibi) == SIG_IGN)
  323.     {
  324.         signal(SIGINT, SIG_IGN);
  325.         signal(SIGKILL, SIG_IGN);
  326.     } else
  327.     {
  328.         signal(SIGINT, bibi);
  329.         signal(SIGKILL, bibi);
  330.     }
  331.     signal(SIGTERM, bibi);
  332. #endif
  333.     if ( wcreceive(npats, patts) == ERROR )
  334.     {
  335.         exitcode = 0200;
  336.         canit();
  337.     }
  338.     mode(0);
  339.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  340.         canit();
  341.     if (exitcode)
  342.         cucheck();
  343.     EXIT(exitcode ? exitcode : 0);
  344. }
  345.  
  346. #include    "rzhelp.c"
  347.  
  348. /*
  349.  * Debugging information output interface routine
  350.  */
  351. /* VARARGS1 */
  352. static    void    vfile( CONST char *form, ... )
  353. {
  354.     va_list        arg;
  355.     char        tmp[BUFSIZ];
  356.  
  357.     if ( Verbose > 2 )
  358.     {
  359.         va_start( arg, form );
  360.         vsprintf( tmp, form, arg );
  361.         va_end(arg);
  362.         USR_fputs(tmp, stderr );
  363.         USR_fputs("\n",stderr);
  364.     }
  365. }
  366.  
  367. /*
  368.  * Let's receive something already.
  369.  */
  370.  
  371. #ifndef    __TOWNS__
  372. static    char    *rbmsg =
  373. "%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n\n";
  374. #endif
  375.  
  376. static    int        wcreceive(int argc, char **argp)
  377. {
  378.     register    c;
  379.  
  380.     if (Batch || argc == 0)
  381.     {
  382.         Crcflg = 1;
  383. #ifdef    __TOWNS__
  384.         USR_fprintf(stderr,
  385.             "rx ready. To begin transfer, type \"%s file ...\" to your modem program\r\n",
  386.             Nozmodem ? "sb" : "sz" );
  387. #else
  388.         USR_fprintf(stderr, rbmsg, Progname, Nozmodem ? "sb" : "sz");
  389. #endif
  390.         if ( (c = tryz()) != 0 )
  391.         {
  392.             if (c == ZCOMPL)
  393.                 return OK;
  394.             if (c == ERROR)
  395.                 goto fubar;
  396.             c = rzfiles();
  397.             if (c)
  398.                 goto fubar;
  399.         } else
  400.         {
  401.             for (;;)
  402.             {
  403.                 if (wcrxpn(secbuf) == ERROR)
  404.                     goto fubar;
  405.                 if (secbuf[0] == 0)
  406.                     return OK;
  407.                 if (procheader(secbuf) == ERROR)
  408.                     goto fubar;
  409.                 if (wcrx() == ERROR)
  410.                     goto fubar;
  411.             }
  412.         }
  413.     } else
  414.     {
  415.         Bytesleft = DEFBYTL;
  416.         Filemode = 0;
  417.         Modtime = 0L;
  418.  
  419.         procheader("");
  420.         strcpy(Pathname, *argp);
  421.         checkpath(Pathname);
  422.         USR_fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
  423.         if ((fout = FM_fopen(Pathname, "wb")) == NULL)
  424.             return ERROR;
  425.         if (wcrx() == ERROR)
  426.             goto fubar;
  427.     }
  428.     return OK;
  429.   fubar:
  430.     canit();
  431. #ifndef    __TOWNS__
  432.     if (Topipe && fout)
  433.     {
  434.         pclose(fout);
  435.         return ERROR;
  436.     }
  437. #endif
  438.     Modtime = 1;
  439.     if (fout)
  440.         FM_fclose(fout);
  441.     if (Restricted)
  442.     {
  443.         unlink(Pathname);
  444.         USR_fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
  445.     }
  446.     return ERROR;
  447. }
  448.  
  449.  
  450. /*
  451.  * Fetch a pathname from the other end as a C ctyle ASCIZ string. Length is
  452.  * indeterminate as long as less than Blklen A null string represents no more
  453.  * files (YMODEM)
  454.  */
  455. static    int        wcrxpn(char *rpn)
  456. /* receive a pathname */
  457. {
  458.     register    c;
  459.  
  460. #ifdef NFGVMIN
  461.     readline(1);
  462. #else
  463.     purgeline();
  464. #endif
  465.  
  466.   et_tu:
  467.     Firstsec = TRUE;
  468.     Eofseen = FALSE;
  469.     sendline(Crcflg ? WANTCRC : NAK);
  470.     Lleft = 0;                    /* Do read next time ... */
  471.     while ((c = wcgetsec(rpn, 100)) != 0)
  472.     {
  473.         if (c == WCEOT)
  474.         {
  475.             zperr("Pathname fetch returned %d", c);
  476.             sendline(ACK);
  477.             Lleft = 0;            /* Do read next time ... */
  478.             readline(1);
  479.             goto et_tu;
  480.         }
  481.         return ERROR;
  482.     }
  483.     sendline(ACK);
  484.     return OK;
  485. }
  486.  
  487. /*
  488.  * Adapted from CMODEM13.C, written by Jack M. Wierda and Roderick W. Hart
  489.  */
  490.  
  491. static    int        wcrx(void)
  492. {
  493.     register int sectnum, sectcurr;
  494.     register char sendchar;
  495.     register char *p;
  496.     int         cblklen;        /* bytes to dump this block */
  497.  
  498.     Firstsec = TRUE;
  499.     sectnum = 0;
  500.     Eofseen = FALSE;
  501.     sendchar = Crcflg ? WANTCRC : NAK;
  502.  
  503.     for (;;)
  504.     {
  505.         sendline(sendchar);     /* send it now, we're ready! */
  506.         Lleft = 0;                /* Do read next time ... */
  507.         sectcurr = wcgetsec(secbuf, (sectnum & 0177) ? 50 : 130);
  508.         report(sectcurr);
  509.         if (sectcurr == (sectnum + 1 & 0377))
  510.         {
  511.             sectnum++;
  512.             cblklen = Bytesleft > Blklen ? Blklen : Bytesleft;
  513.             if (putsec(secbuf, cblklen) == ERROR)
  514.                 return ERROR;
  515.             if ((Bytesleft -= cblklen) < 0)
  516.                 Bytesleft = 0;
  517.             sendchar = ACK;
  518.         } else if (sectcurr == (sectnum & 0377))
  519.         {
  520.             zperr("Received dup Sector");
  521.             sendchar = ACK;
  522.         } else if (sectcurr == WCEOT)
  523.         {
  524.             if (closeit())
  525.                 return ERROR;
  526.             sendline(ACK);
  527.             Lleft = 0;            /* Do read next time ... */
  528.             return OK;
  529.         } else if (sectcurr == ERROR)
  530.             return ERROR;
  531.         else
  532.         {
  533.             zperr("Sync Error");
  534.             return ERROR;
  535.         }
  536.     }
  537. }
  538.  
  539. /*
  540.  * Wcgetsec fetches a Ward Christensen type sector. Returns sector number
  541.  * encountered or ERROR if valid sector not received, or CAN CAN received or
  542.  * WCEOT if eot sector time is timeout for first char, set to 4 seconds
  543.  * thereafter **************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  544.  * (Caller must do that when he is good and ready to get next sector)
  545.  */
  546.  
  547. static    int        wcgetsec(char *rxbuf, int maxtime)
  548. {
  549.     register    checksum, wcj, firstch;
  550.     register unsigned short oldcrc;
  551.     register char *p;
  552.     int         sectcurr;
  553.  
  554.     for (Lastrx = errors = 0; errors < RETRYMAX; errors++)
  555.     {
  556.  
  557.         if ((firstch = readline(maxtime)) == STX)
  558.         {
  559.             Blklen = 1024;
  560.             goto get2;
  561.         }
  562.         if (firstch == SOH)
  563.         {
  564.             Blklen = 128;
  565.           get2:
  566.             sectcurr = readline(1);
  567.             if ((sectcurr + (oldcrc = readline(1))) == 0377)
  568.             {
  569.                 oldcrc = checksum = 0;
  570.                 for (p = rxbuf, wcj = Blklen; --wcj >= 0;)
  571.                 {
  572.                     if ((firstch = readline(1)) < 0)
  573.                         goto bilge;
  574.                     oldcrc = updcrc(firstch, oldcrc);
  575.                     checksum += (*p++ = firstch);
  576.                 }
  577.                 if ((firstch = readline(1)) < 0)
  578.                     goto bilge;
  579.                 if (Crcflg)
  580.                 {
  581.                     oldcrc = updcrc(firstch, oldcrc);
  582.                     if ((firstch = readline(1)) < 0)
  583.                         goto bilge;
  584.                     oldcrc = updcrc(firstch, oldcrc);
  585.                     if (oldcrc & 0xFFFF)
  586.                         zperr("CRC");
  587.                     else
  588.                     {
  589.                         Firstsec = FALSE;
  590.                         return sectcurr;
  591.                     }
  592.                 } else if (((checksum - firstch) & 0377) == 0)
  593.                 {
  594.                     Firstsec = FALSE;
  595.                     return sectcurr;
  596.                 } else
  597.                     zperr("Checksum");
  598.             } else
  599.                 zperr("Sector number garbled");
  600.         }
  601.         /* make sure eot really is eot and not just mixmash */
  602. #ifdef NFGVMIN
  603.         else if (firstch == EOT && readline(1) == TIMEOUT)
  604.             return WCEOT;
  605. #else
  606.         else if (firstch == EOT && Lleft == 0)
  607.             return WCEOT;
  608. #endif
  609.         else if (firstch == CAN)
  610.         {
  611.             if (Lastrx == CAN)
  612.             {
  613.                 zperr("Sender CANcelled");
  614.                 return ERROR;
  615.             } else
  616.             {
  617.                 Lastrx = CAN;
  618.                 continue;
  619.             }
  620.         } else if (firstch == TIMEOUT)
  621.         {
  622.             if (Firstsec)
  623.                 goto humbug;
  624.           bilge:
  625.             zperr("TIMEOUT");
  626.         } else
  627.             zperr("Got 0%o sector header", firstch);
  628.  
  629.       humbug:
  630.         Lastrx = 0;
  631.         while (readline(1) != TIMEOUT)
  632.             ;
  633.         if (Firstsec)
  634.         {
  635.             sendline(Crcflg ? WANTCRC : NAK);
  636.             Lleft = 0;            /* Do read next time ... */
  637.         } else
  638.         {
  639.             maxtime = 40;
  640.             sendline(NAK);
  641.             Lleft = 0;            /* Do read next time ... */
  642.         }
  643.     }
  644.     /* try to stop the bubble machine. */
  645.     canit();
  646.     return ERROR;
  647. }
  648.  
  649. /*
  650.  * This version of readline is reasoably well suited for reading many
  651.  * characters. (except, currently, for the Regulus version!)
  652.  *
  653.  * timeout is in tenths of seconds
  654.  */
  655. static    int        readline(int timeout)
  656. {
  657.     register    n;
  658.     static char *cdq;            /* pointer for removing chars from linbuf */
  659.  
  660.     if ( --Lleft >= 0 )
  661.     {
  662.         if (Verbose > 8)
  663.         {
  664.             USR_fprintf(stderr, "%02x ", *cdq & 0377);
  665.         }
  666.         return (*cdq++ & 0377);
  667.     }
  668.  
  669. #ifdef    __TOWNS__
  670.     n = timeout;
  671.     if (n < 200 )
  672.         n = 200;
  673. #else
  674.     n = timeout / 10;
  675.     if (n < 2)
  676.         n = 3;
  677. #endif
  678.     if (Verbose > 5)
  679.         USR_fprintf(stderr, "Calling read: alarm=%d  Readnum=%d ",
  680.                 n, Readnum);
  681. #ifdef    __TOWNS__
  682.     {
  683.         clock_t    clk;
  684.         clk = H_CLOCK2(0) + n * CLOCKS_PER_SEC / 100;
  685.         int        c;
  686.  
  687.         do
  688.         {
  689.             if (  (c = RS_chk(RsPort)) > 0 )
  690.             {
  691.                 int        i;
  692.                 i = 0;
  693.                 while ( i < Readnum )
  694.                 {
  695.                     linbuf[i++] = RS_getc(RsPort);
  696.                     if ( RS_chk(RsPort) < 1 )
  697.                         break;
  698.                 }
  699.                 cdq = linbuf;
  700.                 Lleft = i;
  701.                 break;
  702.             }
  703.         } while ( clk > H_CLOCK2(clk) );
  704.  
  705.         if ( c < 1 )
  706.         {    /* timeout */
  707.             Lleft = 0;
  708.             if (Verbose > 1)
  709.                 USR_fprintf(stderr, "Readline:TIMEOUT\n");
  710.             return TIMEOUT;
  711.         }
  712.     }
  713. #else
  714.     if (setjmp(tohere))
  715.     {
  716. #ifdef TIOCFLUSH
  717.         /* ioctl(0, TIOCFLUSH, 0); */
  718. #endif
  719.         Lleft = 0;
  720.         if (Verbose > 1)
  721.             fprintf(stderr, "Readline:TIMEOUT\n");
  722.         return TIMEOUT;
  723.     }
  724.     signal(SIGALRM, alrm);
  725.     alarm(n);
  726.     Lleft = read(0, cdq = linbuf, Readnum);
  727.     alarm(0);
  728. #endif
  729.     if (Verbose > 5)
  730.     {
  731.         USR_fprintf(stderr, "Read returned %d bytes\n", Lleft);
  732.     }
  733.     if (Lleft < 1)
  734.         return TIMEOUT;
  735.     --Lleft;
  736.     if (Verbose > 8)
  737.     {
  738.         USR_fprintf(stderr, "%02X ", *cdq & 0377);
  739.     }
  740.     return (*cdq++ & 0377);
  741. }
  742.  
  743.  
  744.  
  745. /*
  746.  * Purge the modem input queue of all characters
  747.  */
  748. static    void    purgeline(void)
  749. {
  750.     Lleft = 0;
  751. #ifndef    __TOWNS__
  752. #    ifdef USG
  753.         ioctl(0, TCFLSH, 0);
  754. #    else
  755.         lseek(0, 0L, 2);
  756. #    endif
  757. #endif
  758. }
  759.  
  760.  
  761. /*
  762.  * Process incoming file information header
  763.  */
  764. static    int        procheader(char *name)
  765. {
  766.     register char *openmode, *p, **pp;
  767.     static        dummy;
  768.     struct stat f;
  769.  
  770.     /* set default parameters and overrides */
  771.     openmode = "wb";
  772.  
  773.     /*
  774.      * Process ZMODEM remote file management requests
  775.      */
  776.     Thisbinary = (zconv != ZCNL);        /* Remote ASCII override */
  777.     if (zmanag == ZMAPND)
  778.         openmode = "ab";
  779.  
  780.     Bytesleft = DEFBYTL;
  781.     Filemode = 0;
  782.     Modtime = 0L;
  783.  
  784.     p = name + 1 + strlen(name);
  785.     if (*p)
  786.     {                            /* file coming from Unix or DOS system */
  787.         sscanf(p, "%ld%lo%o%lo%d%ld%d%d",
  788.                &Bytesleft, &Modtime, &Filemode,
  789.                &dummy, &Filesleft, &Totalleft, &dummy, &dummy);
  790.         if (Filemode & UNIXFILE)
  791.             ++Thisbinary;
  792.         if (Verbose)
  793.         {
  794.             USR_fprintf(stderr, "\nIncoming: %s %ld %lo %o\n",
  795.                     name, Bytesleft, Modtime, Filemode);
  796.             USR_fprintf(stderr, "YMODEM header: %s\n", p);
  797.         }
  798.     } else
  799.     {
  800. #ifdef    __TOWNS__
  801. #else
  802.         /* File coming from CP/M system */
  803.         for (p = name; *p; ++p) /* change / to _ */
  804.             if (*p == '/')
  805.                 *p = '_';
  806.  
  807.         if (*--p == '.')        /* zap trailing period */
  808.             *p = 0;
  809. #endif
  810.     }
  811.  
  812.     strcpy(Pathname, name);
  813.     checkpath(name);
  814.  
  815.     if (*name && stat(name, &f) != -1)
  816.     {
  817.         zmanag &= ZMMASK;
  818.         vfile("Current %s is %ld %lo", name, f.st_size, f.st_mtime);
  819.         if (Thisbinary && zconv == ZCRESUM)
  820.         {
  821.             rxbytes = f.st_size & ~511;
  822.             openit(name, "r+b");
  823.             if (!fout)
  824.                 return ZFERR;
  825.             if (Bytesleft < rxbytes)
  826.                 rxbytes = 0;
  827.             if (fseek(fout, rxbytes, 0))
  828.             {
  829.                 closeit();
  830.                 return ZFERR;
  831.             }
  832.             vfile("Crash recovery at %ld", rxbytes);
  833.             return 0;
  834.         } else if ((zmanag == ZMNEW) ||
  835.                    ((zmanag == ZMNEWL) && Bytesleft <= f.st_size))
  836.         {
  837.             if ((f.st_mtime + 1) >= Modtime)
  838.                 goto skipfile;
  839.             goto doopen;
  840.         } else if (zmanag == ZMPROT)
  841.             goto skipfile;
  842.         else if ((zmanag & ZMMASK) != ZMCLOB)
  843.             goto skipfile;
  844.         goto doopen;
  845.     } else if (zmanag & ZMSKNOLOC)
  846.     {
  847.       skipfile:
  848.         vfile("Skipping %s", name);
  849.         return ZSKIP;
  850.     }
  851.   doopen:
  852.     openit(name, openmode);
  853. #ifdef MD
  854.     if (!fout)
  855.         if (make_dirs(name))
  856.             openit(name, openmode);
  857. #endif
  858.     if (!fout)
  859.         return ZFERR;
  860.     return 0;
  861. }
  862.  
  863. static    void    openit(char *name, char *openmode)
  864. {
  865. #ifdef    DEBUG
  866.     USR_fprintf(stderr,"\nfopen(\x22%s\x22,\x22%s\x22)\n", name, openmode);
  867. #endif
  868.     fout = FM_fopen(name, openmode);
  869. }
  870.  
  871. #ifdef MD
  872. /*
  873.  * Directory-creating routines from Public Domain TAR by John Gilmore
  874.  */
  875.  
  876. /*
  877.  * After a file/link/symlink/dir creation has failed, see if it's because
  878.  * some required directory was not present, and if so, create all required
  879.  * dirs.
  880.  */
  881. static    int        make_dirs(register char *pathname)
  882. {
  883.     register char *p;            /* Points into path */
  884.     int         madeone = 0;    /* Did we do anything yet? */
  885.     int         save_errno = errno;     /* Remember caller's errno */
  886.  
  887.     if (errno != ENOENT)
  888.         return 0;                /* Not our problem */
  889.  
  890.     for (p = strchr(pathname, '/'); p != NULL; p = strchr(p + 1, '/'))
  891.     {
  892.         /* Avoid mkdir of empty string, if leading or double '/' */
  893.         if (p == pathname || p[-1] == '/')
  894.             continue;
  895.         /* Avoid mkdir where last part of path is '.' */
  896.         if (p[-1] == '.' && (p == pathname + 1 || p[-2] == '/'))
  897.             continue;
  898.         *p = 0;                 /* Truncate the path there */
  899. #ifdef    __TOWNS__
  900.         if (!_mkdir(pathname))
  901. #else
  902.         if (!mkdir(pathname, 0777))
  903. #endif
  904.         {                        /* Try to create it as a dir */
  905.             vfile("Made directory %s\n", pathname);
  906.             madeone++;            /* Remember if we made one */
  907.             *p = '/';
  908.             continue;
  909.         }
  910.         *p = '/';
  911.         if (errno == EEXIST)    /* Directory already exists */
  912.             continue;
  913.         /*
  914.          * Some other error in the mkdir.  We return to the caller.
  915.          */
  916.         break;
  917.     }
  918.     errno = save_errno;         /* Restore caller's errno */
  919.     return madeone;             /* Tell them to retry if we made one */
  920. }
  921.  
  922. #ifndef    __TOWNS__
  923. #if (MD != 2)
  924. #define TERM_SIGNAL(status)     ((status) & 0x7F)
  925. #define TERM_COREDUMP(status)    (((status) & 0x80) != 0)
  926. #define TERM_VALUE(status)        ((status) >> 8)
  927. /*
  928.  * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
  929.  */
  930. static    int        mkdir(char *dpath, int dmode)
  931. {
  932.     int         cpid, status;
  933.     struct stat statbuf;
  934.  
  935.     if (stat(dpath, &statbuf) == 0)
  936.     {
  937.         errno = EEXIST;         /* Stat worked, so it already exists */
  938.         return -1;
  939.     }
  940.     /* If stat fails for a reason other than non-existence, return error */
  941.     if (errno != ENOENT)
  942.         return -1;
  943.  
  944.     switch (cpid = fork())
  945.     {
  946.  
  947.         case -1:                /* Error in fork() */
  948.             return (-1);        /* Errno is set already */
  949.  
  950.         case 0:         /* Child process */
  951.             /*
  952.              * Cheap hack to set mode of new directory.  Since this child
  953.              * process is going away anyway, we zap its umask. FIXME, this
  954.              * won't suffice to set SUID, SGID, etc. on this directory.  Does
  955.              * anybody care?
  956.              */
  957.             status = umask(0);    /* Get current umask */
  958.             status = umask(status | (0777 & ~dmode));    /* Set for mkdir */
  959.             execl("/bin/mkdir", "mkdir", dpath, (char *) 0);
  960.             _exit(-1);            /* Can't exec /bin/mkdir */
  961.  
  962.         default:                /* Parent process */
  963.             while (cpid != wait(&status));        /* Wait for kid to finish */
  964.     }
  965.  
  966.     if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0)
  967.     {
  968.         errno = EIO;            /* We don't know why, but */
  969.         return -1;                /* /bin/mkdir failed */
  970.     }
  971.     return 0;
  972. }
  973. #endif                            /* MD != 2 */
  974. #endif                            /* endof ifndef __TOWNS__ */
  975. #endif                            /* MD */
  976.  
  977. /*
  978.  * Putsec writes the n characters of buf to receive file fout. If not in
  979.  * binary mode, carriage returns, and all characters starting with CPMEOF are
  980.  * discarded.
  981.  */
  982. static    int        putsec(char *buf, register n)
  983. {
  984.     register char *p;
  985.  
  986.     if (n == 0)
  987.         return OK;
  988.     if (Thisbinary)
  989.     {
  990.         for (p = buf; --n >= 0;)
  991.         {
  992.             putc(*p, fout);
  993.             ++p;
  994.         }
  995.     } else
  996.     {
  997.         if (Eofseen)
  998.             return OK;
  999.         for (p = buf; --n >= 0; ++p)
  1000.         {
  1001.             if (*p == '\r')
  1002.                 continue;
  1003.             if (*p == CPMEOF)
  1004.             {
  1005.                 Eofseen = TRUE;
  1006.                 return OK;
  1007.             }
  1008.             putc(*p, fout);
  1009.         }
  1010.     }
  1011.     return OK;
  1012. }
  1013.  
  1014. /*
  1015.  * Send a character to modem.  Small is beautiful.
  1016.  */
  1017. static    void    sendline(int c)
  1018. {
  1019.     c &= 0xFF;
  1020.     if (Verbose > 6)
  1021.         USR_fprintf(stderr, "Sendline: %x\n", c);
  1022. #ifdef    __TOWNS__
  1023.     RS_putc( RsPort, c );
  1024. #else
  1025.     char        d;
  1026.     d = c;
  1027.     write(1, &d, 1);
  1028. #endif
  1029. }
  1030.  
  1031. static    void    flushmo(void)
  1032. {
  1033. }
  1034. static    void    flushmoc(void)
  1035. {
  1036. }
  1037.  
  1038. /*
  1039.  * substr(string, token) searches for token in string s returns pointer to
  1040.  * token within string if found, NULL otherwise
  1041.  */
  1042. static    char       *substr(register char *s, register char *t)
  1043. {
  1044.     register char *ss, *tt;
  1045.     /* search for first char of token */
  1046.     for (ss = s; *s; s++)
  1047.         if (*s == *t)
  1048.             /* compare token with substring */
  1049.             for (ss = s, tt = t;;)
  1050.             {
  1051.                 if (*tt == 0)
  1052.                     return s;
  1053.                 if (*ss++ != *tt++)
  1054.                     break;
  1055.             }
  1056.     return NULL;
  1057. }
  1058.  
  1059. /*
  1060.  * Log an error
  1061.  */
  1062. /* VARARGS1 */
  1063. static    void    zperr(char *form, ... )
  1064. {
  1065.     va_list        arg;
  1066.     char        tmp[BUFSIZ];
  1067.  
  1068.     if (Verbose <= 0)
  1069.         return;
  1070.     USR_fprintf(stderr, "Retry %d: ", errors);
  1071.     va_start( arg, form );
  1072.     vsprintf( tmp, form, arg );
  1073.     va_end(arg);
  1074.     USR_fputs(tmp, stderr );
  1075.     USR_fputs("\n",stderr);
  1076. }
  1077.  
  1078. /* send cancel string to get the other end to shut up */
  1079. static    void    canit(void)
  1080. {
  1081.     static char canistr[] =
  1082.     {
  1083.      24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0
  1084.     };
  1085.  
  1086.     RS_puts(RsPort,canistr);
  1087.     Lleft = 0;                    /* Do read next time ... */
  1088. }
  1089.  
  1090.  
  1091. static    void    report(int sct)
  1092. {
  1093.     if (Verbose > 1)
  1094.         USR_fprintf(stderr, "%03d%c", sct, sct % 10 ? ' ' : '\r');
  1095. }
  1096.  
  1097. /*
  1098.  * If called as [-][dir/../]vrzCOMMAND set Verbose to 1 If called as
  1099.  * [-][dir/../]rzCOMMAND set the pipe flag If called as rb use YMODEM
  1100.  * protocol
  1101.  */
  1102. static    void    chkinvok(char *s)
  1103. {
  1104.     register char *p;
  1105.  
  1106.     p = s;
  1107.     while (*p == '-')
  1108.         s = ++p;
  1109.     while (*p)
  1110.         if (*p++ == '/')
  1111.             s = p;
  1112.     if (*s == 'v')
  1113.     {
  1114.         Verbose = 1;
  1115.         ++s;
  1116.     }
  1117.     Progname = s;
  1118.     if (s[0] == 'r' && s[1] == 'z')
  1119.         Batch = TRUE;
  1120.     if (s[0] == 'r' && s[1] == 'b')
  1121.         Batch = Nozmodem = TRUE;
  1122. #ifndef    __TOWNS__
  1123.     if (s[2] && s[0] == 'r' && s[1] == 'b')
  1124.         Topipe = 1;
  1125.     if (s[2] && s[0] == 'r' && s[1] == 'z')
  1126.         Topipe = 1;
  1127. #endif
  1128. }
  1129.  
  1130. /*
  1131.  * Totalitarian Communist pathname processing
  1132.  */
  1133. static    void    checkpath(char *name)
  1134. {
  1135.     if (Restricted)
  1136.     {
  1137.         FILE    *fp;
  1138.         
  1139.         if ( (fp = FM_fopen(name, "rb")) != NULL)
  1140.         {
  1141.             canit();
  1142.             USR_fprintf(stderr, "\r\nrz: %s exists\n", name);
  1143.             FM_fclose(fp);
  1144.             bibi(-1);
  1145.         }
  1146.         /* restrict pathnames to current tree or uucppublic */
  1147.         if (substr(name, "../")
  1148.             || (name[0] == '/' && strncmp(name, PUBDIR, strlen(PUBDIR))))
  1149.         {
  1150.             canit();
  1151.             USR_fprintf(stderr, "\r\nrz:\tSecurity Violation\r\n");
  1152.             bibi(-1);
  1153.         }
  1154.     }
  1155. }
  1156.  
  1157. /*
  1158.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  1159.  * Handles ZSINIT frame Return ZFILE if Zmodem filename received, -1 on
  1160.  * error, ZCOMPL if transaction finished,  else 0
  1161.  */
  1162. static    int        tryz(void)
  1163. {
  1164.     register    c, n;
  1165.     register    cmdzack1flg;
  1166.  
  1167.     if (Nozmodem)                /* Check for "rb" program name */
  1168.         return 0;
  1169.  
  1170.  
  1171.     for (n = Zmodem ? 15 : 5; --n >= 0;)
  1172.     {
  1173.         /* Set buffer length (0) and capability flags */
  1174. #ifdef SEGMENTS
  1175.         stohdr(SEGMENTS * 1024L);
  1176. #else
  1177.         stohdr(0L);
  1178. #endif
  1179. #ifdef CANBREAK
  1180.         Txhdr[ZF0] = CANFC32 | CANFDX | CANOVIO | CANBRK;
  1181. #else
  1182.         Txhdr[ZF0] = CANFC32 | CANFDX | CANOVIO;
  1183. #endif
  1184.         if (Zctlesc)
  1185.             Txhdr[ZF0] |= TESCCTL;
  1186.         Txhdr[ZF0] |= CANRLE;
  1187.         Txhdr[ZF1] = CANVHDR;
  1188.         /* tryzhdrtype may == ZRINIT */
  1189.         zshhdr(4, tryzhdrtype, Txhdr);
  1190.         if (tryzhdrtype == ZSKIP)        /* Don't skip too far */
  1191.             tryzhdrtype = ZRINIT;        /* CAF 8-21-87 */
  1192.       again:
  1193.         switch (zgethdr(Rxhdr, 0))
  1194.         {
  1195.             case ZRQINIT:
  1196.                 if (Rxhdr[ZF3] & 0x80)
  1197.                     Usevhdrs = 1;        /* we can var header */
  1198.                 continue;
  1199.             case ZEOF:
  1200.                 continue;
  1201.             case TIMEOUT:
  1202.                 continue;
  1203.             case ZFILE:
  1204.                 zconv = Rxhdr[ZF0];
  1205.                 zmanag = Rxhdr[ZF1];
  1206.                 ztrans = Rxhdr[ZF2];
  1207.                 if (Rxhdr[ZF3] & ZCANVHDR)
  1208.                     Usevhdrs = TRUE;
  1209.                 tryzhdrtype = ZRINIT;
  1210.                 c = zrdata(secbuf, 1024);
  1211.                 mode(3);
  1212.                 if (c == GOTCRCW)
  1213.                     return ZFILE;
  1214.                 zshhdr(4, ZNAK, Txhdr);
  1215.                 goto again;
  1216.             case ZSINIT:
  1217.                 Zctlesc = TESCCTL & Rxhdr[ZF0];
  1218.                 if (zrdata(Attn, ZATTNLEN) == GOTCRCW)
  1219.                 {
  1220.                     stohdr(1L);
  1221.                     zshhdr(4, ZACK, Txhdr);
  1222.                     goto again;
  1223.                 }
  1224.                 zshhdr(4, ZNAK, Txhdr);
  1225.                 goto again;
  1226.             case ZFREECNT:
  1227.                 stohdr(getfree());
  1228.                 zshhdr(4, ZACK, Txhdr);
  1229.                 goto again;
  1230.             case ZCOMMAND:
  1231.                 cmdzack1flg = Rxhdr[ZF0];
  1232.                 if (zrdata(secbuf, 1024) == GOTCRCW)
  1233.                 {
  1234.                     if (cmdzack1flg & ZCACK1)
  1235.                         stohdr(0L);
  1236.                     else
  1237.                         stohdr((long) sys2(secbuf));
  1238.                     purgeline();/* dump impatient questions */
  1239.                     do
  1240.                     {
  1241.                         zshhdr(4, ZCOMPL, Txhdr);
  1242.                     }
  1243.                     while (++errors < 20 && zgethdr(Rxhdr, 1) != ZFIN);
  1244.                     ackbibi();
  1245.                     if (cmdzack1flg & ZCACK1)
  1246.                         exec2(secbuf);
  1247.                     return ZCOMPL;
  1248.                 }
  1249.                 zshhdr(4, ZNAK, Txhdr);
  1250.                 goto again;
  1251.             case ZCOMPL:
  1252.                 goto again;
  1253.             default:
  1254.                 continue;
  1255.             case ZFIN:
  1256.                 ackbibi();
  1257.                 return ZCOMPL;
  1258.             case ZCAN:
  1259.                 return ERROR;
  1260.         }
  1261.     }
  1262.     return 0;
  1263. }
  1264.  
  1265. /*
  1266.  * Receive 1 or more files with ZMODEM protocol
  1267.  */
  1268. static    int        rzfiles(void)
  1269. {
  1270.     register    c;
  1271.  
  1272.     for (;;)
  1273.     {
  1274.         switch (c = rzfile())
  1275.         {
  1276.             case ZEOF:
  1277.             case ZSKIP:
  1278.                 switch (tryz())
  1279.                 {
  1280.                     case ZCOMPL:
  1281.                         return OK;
  1282.                     default:
  1283.                         return ERROR;
  1284.                     case ZFILE:
  1285.                         break;
  1286.                 }
  1287.                 continue;
  1288.             default:
  1289.                 return c;
  1290.             case ERROR:
  1291.                 return ERROR;
  1292.         }
  1293.     }
  1294. }
  1295.  
  1296. /*
  1297.  * Receive a file with ZMODEM protocol Assumes file name frame is in secbuf
  1298.  */
  1299. static    int        rzfile(void)
  1300. {
  1301.     register    c, n;
  1302.     long        rxbytes;
  1303.  
  1304.     Eofseen = FALSE;
  1305.     if (procheader(secbuf) == ERROR)
  1306.     {
  1307.         return (tryzhdrtype = ZSKIP);
  1308.     }
  1309.     n = 20;
  1310.     rxbytes = 0l;
  1311.  
  1312.     for (;;)
  1313.     {
  1314. #ifdef SEGMENTS
  1315.         chinseg = 0;
  1316. #endif
  1317.         stohdr(rxbytes);
  1318.         zshhdr(4, ZRPOS, Txhdr);
  1319.       nxthdr:
  1320.         switch (c = zgethdr(Rxhdr, 0))
  1321.         {
  1322.             default:
  1323.                 vfile("rzfile: zgethdr returned %d", c);
  1324.                 return ERROR;
  1325.             case ZNAK:
  1326.             case TIMEOUT:
  1327. #ifdef SEGMENTS
  1328.                 putsec(secbuf, chinseg);
  1329.                 chinseg = 0;
  1330. #endif
  1331.                 if (--n < 0)
  1332.                 {
  1333.                     vfile("rzfile: zgethdr returned %d", c);
  1334.                     return ERROR;
  1335.                 }
  1336.             case ZFILE:
  1337.                 zrdata(secbuf, 1024);
  1338.                 continue;
  1339.             case ZEOF:
  1340. #ifdef SEGMENTS
  1341.                 putsec(secbuf, chinseg);
  1342.                 chinseg = 0;
  1343. #endif
  1344.                 if (rclhdr(Rxhdr) != rxbytes)
  1345.                 {
  1346.                     /*
  1347.                      * Ignore eof if it's at wrong place - force a timeout
  1348.                      * because the eof might have gone out before we sent our
  1349.                      * zrpos.
  1350.                      */
  1351.                     errors = 0;
  1352.                     goto nxthdr;
  1353.                 }
  1354.                 if (closeit())
  1355.                 {
  1356.                     tryzhdrtype = ZFERR;
  1357.                     vfile("rzfile: closeit returned <> 0");
  1358.                     return ERROR;
  1359.                 }
  1360.                 vfile("rzfile: normal EOF");
  1361.                 return c;
  1362.             case ERROR: /* Too much garbage in header search error */
  1363. #ifdef SEGMENTS
  1364.                 putsec(secbuf, chinseg);
  1365.                 chinseg = 0;
  1366. #endif
  1367.                 if (--n < 0)
  1368.                 {
  1369.                     vfile("rzfile: zgethdr returned %d", c );
  1370.                     return ERROR;
  1371.                 }
  1372.                 zmputs(Attn);
  1373.                 continue;
  1374.             case ZSKIP:
  1375. #ifdef SEGMENTS
  1376.                 putsec(secbuf, chinseg);
  1377.                 chinseg = 0;
  1378. #endif
  1379.                 Modtime = 1;
  1380.                 closeit();
  1381.                 vfile("rzfile: Sender SKIPPED file");
  1382.                 return c;
  1383.             case ZDATA:
  1384.                 if (rclhdr(Rxhdr) != rxbytes)
  1385.                 {
  1386.                     if (--n < 0)
  1387.                     {
  1388.                         return ERROR;
  1389.                     }
  1390. #ifdef SEGMENTS
  1391.                     putsec(secbuf, chinseg);
  1392.                     chinseg = 0;
  1393. #endif
  1394.                     zmputs(Attn);
  1395.                     continue;
  1396.                 }
  1397.               moredata:
  1398.                 if (Verbose > 1)
  1399.                     USR_fprintf(stderr, "\r%7ld ZMODEM%s    ",
  1400.                             rxbytes, Crc32r ? " CRC-32" : "");
  1401. #ifdef SEGMENTS
  1402.                 if (chinseg >= (1024 * SEGMENTS))
  1403.                 {
  1404.                     putsec(secbuf, chinseg);
  1405.                     chinseg = 0;
  1406.                 }
  1407.                 switch (c = zrdata(secbuf + chinseg, 1024))
  1408. #else
  1409.                 switch (c = zrdata(secbuf, 1024))
  1410. #endif
  1411.                 {
  1412.                     case ZCAN:
  1413. #ifdef SEGMENTS
  1414.                         putsec(secbuf, chinseg);
  1415.                         chinseg = 0;
  1416. #endif
  1417.                         vfile("rzfile: zgethdr returned %d", c);
  1418.                         return ERROR;
  1419.                     case ERROR:/* CRC error */
  1420. #ifdef SEGMENTS
  1421.                         putsec(secbuf, chinseg);
  1422.                         chinseg = 0;
  1423. #endif
  1424.                         if (--n < 0)
  1425.                         {
  1426.                             vfile("rzfile: zgethdr returned %d", c);
  1427.                             return ERROR;
  1428.                         }
  1429.                         zmputs(Attn);
  1430.                         continue;
  1431.                     case TIMEOUT:
  1432. #ifdef SEGMENTS
  1433.                         putsec(secbuf, chinseg);
  1434.                         chinseg = 0;
  1435. #endif
  1436.                         if (--n < 0)
  1437.                         {
  1438.                             vfile("rzfile: zgethdr returned %d", c);
  1439.                             return ERROR;
  1440.                         }
  1441.                         continue;
  1442.                     case GOTCRCW:
  1443.                         n = 20;
  1444. #ifdef SEGMENTS
  1445.                         chinseg += Rxcount;
  1446.                         putsec(secbuf, chinseg);
  1447.                         chinseg = 0;
  1448. #else
  1449.                         putsec(secbuf, Rxcount);
  1450. #endif
  1451.                         rxbytes += Rxcount;
  1452.                         stohdr(rxbytes);
  1453.                         zshhdr(4, ZACK, Txhdr);
  1454.                         sendline(XON);
  1455.                         goto nxthdr;
  1456.                     case GOTCRCQ:
  1457.                         n = 20;
  1458. #ifdef SEGMENTS
  1459.                         chinseg += Rxcount;
  1460. #else
  1461.                         putsec(secbuf, Rxcount);
  1462. #endif
  1463.                         rxbytes += Rxcount;
  1464.                         stohdr(rxbytes);
  1465.                         zshhdr(4, ZACK, Txhdr);
  1466.                         goto moredata;
  1467.                     case GOTCRCG:
  1468.                         n = 20;
  1469. #ifdef SEGMENTS
  1470.                         chinseg += Rxcount;
  1471. #else
  1472.                         putsec(secbuf, Rxcount);
  1473. #endif
  1474.                         rxbytes += Rxcount;
  1475.                         goto moredata;
  1476.                     case GOTCRCE:
  1477.                         n = 20;
  1478. #ifdef SEGMENTS
  1479.                         chinseg += Rxcount;
  1480. #else
  1481.                         putsec(secbuf, Rxcount);
  1482. #endif
  1483.                         rxbytes += Rxcount;
  1484.                         goto nxthdr;
  1485.                 }
  1486.         }
  1487.     }
  1488. }
  1489.  
  1490. /*
  1491.  * Send a string to the modem, processing for \336 (sleep 1 sec) and \335
  1492.  * (break signal)
  1493.  */
  1494. static    void    zmputs(char *s)
  1495. {
  1496.     register    c;
  1497.  
  1498.     while (*s)
  1499.     {
  1500.         switch (c = *s++)
  1501.         {
  1502.             case '\336':
  1503. #ifdef    __TOWNS__
  1504.                 {
  1505.                     clock_t    clk;
  1506.                     clk = H_CLOCK2(0) + 1 * CLOCKS_PER_SEC;
  1507.                     while ( clk > H_CLOCK2(clk) )
  1508.                         ;
  1509.                 }
  1510. #else
  1511.                 sleep(1);
  1512. #endif
  1513.                 continue;
  1514.             case '\335':
  1515.                 sendbrk();
  1516.                 continue;
  1517.             default:
  1518.                 sendline(c);
  1519.         }
  1520.     }
  1521. }
  1522.  
  1523. /*
  1524.  * Close the receive dataset, return OK or ERROR
  1525.  */
  1526. static    int        closeit(void)
  1527. {
  1528. #ifndef    __TOWNS__
  1529.     if (Topipe)
  1530.     {
  1531.         if (pclose(fout))
  1532.         {
  1533.             return ERROR;
  1534.         }
  1535.         return OK;
  1536.     }
  1537. #endif
  1538.     if (FM_fclose(fout) == ERROR)
  1539.     {
  1540.         USR_fprintf(stderr, "file close ERROR\n");
  1541.         return ERROR;
  1542.     }
  1543.     if (Modtime)
  1544.     {
  1545. #ifdef    __TOWNS__
  1546.         struct utimbuf    timbuf;
  1547.         timbuf.actime  = time(NULL);
  1548.         timbuf.modtime = Modtime;
  1549.         _utime(Pathname, &timbuf);
  1550. #else
  1551.         timep[0] = time(NULL);
  1552.         timep[1] = Modtime;
  1553.         utime(Pathname, timep);
  1554. #endif
  1555.     }
  1556.     if ((Filemode & S_IFMT) == S_IFREG)
  1557. #ifdef    __TOWNS__
  1558.         _chmod(Pathname, (07777 & Filemode));
  1559. #else
  1560.         chmod(Pathname, (07777 & Filemode));
  1561. #endif
  1562.     return OK;
  1563. }
  1564.  
  1565. /*
  1566.  * Ack a ZFIN packet, let byegones be byegones
  1567.  */
  1568. static    void    ackbibi(void)
  1569. {
  1570.     register    n;
  1571.  
  1572.     vfile("ackbibi:");
  1573.     Readnum = 1;
  1574.     stohdr(0L);
  1575.     for (n = 3; --n >= 0;)
  1576.     {
  1577.         purgeline();
  1578.         zshhdr(4, ZFIN, Txhdr);
  1579.         switch (readline(100))
  1580.         {
  1581.             case 'O':
  1582.                 readline(1);    /* Discard 2nd 'O' */
  1583.                 vfile("ackbibi complete");
  1584.                 return;
  1585.             case RCDO:
  1586.                 return;
  1587.             case TIMEOUT:
  1588.             default:
  1589.                 break;
  1590.         }
  1591.     }
  1592. }
  1593.  
  1594.  
  1595.  
  1596. /*
  1597.  * Local console output simulation
  1598.  */
  1599. static    void    bttyout(int c)
  1600. {
  1601.     if (Verbose || Fromcu)
  1602.         USR_fputc(c, stderr);
  1603. }
  1604.  
  1605. /*
  1606.  * Strip leading ! if present, do shell escape.
  1607.  */
  1608. static    int        sys2(register char *s)
  1609. {
  1610.     if (*s == '!')
  1611.         ++s;
  1612. #ifndef    __TOWNS__
  1613.     return system(s);
  1614. #else
  1615.     return (1);
  1616. #endif
  1617. }
  1618. /*
  1619.  * Strip leading ! if present, do exec.
  1620.  */
  1621. static    void    exec2(register char *s)
  1622. {
  1623.     if (*s == '!')
  1624.         ++s;
  1625.     mode(0);
  1626. #ifndef    __TOWNS__
  1627.     execl("/bin/sh", "sh", "-c", s);
  1628. #endif
  1629. }
  1630. /* End of rz.c */
  1631.